// tcp-link.ts
import TcpSocket, { Server, Socket } from 'react-native-tcp-socket';
import NetInfo from '@react-native-community/netinfo';
import { AppState, AppStateStatus, Platform } from 'react-native';

type Listener<T extends any[] = any[]> = (...args: T) => void;

class Emitter {
    private map = new Map<string, Set<Listener>>();
    on(evt: string, fn: Listener) { (this.map.get(evt) ?? this.map.set(evt, new Set()).get(evt)!)!.add(fn); return () => this.off(evt, fn); }
    off(evt: string, fn: Listener) { this.map.get(evt)?.delete(fn); }
    emit(evt: string, ...args: any[]) { this.map.get(evt)?.forEach(fn => fn(...args)); }
}

/** 基本配置 */
export type TcpConfig = {
    /** 端口（服务端监听，客户端连接） */
    port: number;
    /** 客户端要连的主机（IP/域名）。若不传，则只启动服务端。 */
    host?: string;
    /** 是否启用客户端自动重连 */
    autoReconnect?: boolean;
    /** 心跳间隔（毫秒）。<=0 则关闭心跳 */
    heartbeatIntervalMs?: number; // e.g. 5000
    /** 心跳内容（字符串或 Buffer） */
    heartbeatPayload?: string | Uint8Array;
    /** 读取超时（毫秒），超时则视为断开重连；不设置则不启用 */
    readIdleTimeoutMs?: number;
    /** 指数退避：初始与最大重连间隔 */
    backoff?: { initialMs: number; maxMs: number; factor?: number; jitter?: number };
};

export type Role = 'server' | 'client' | 'both';

export class TcpLink extends Emitter {
    private cfg: Required<TcpConfig>;
    private role: Role;
    private server: Server | null = null;
    private serverSocket: Socket | null = null; // 接入的客户端（简单场景只接一个）
    private client: Socket | null = null;
    private hbTimer: any = null;
    private idleTimer: any = null;
    private appState: AppStateStatus = 'active';
    private reconnectTimer: any = null;
    private reconnectDelay = 0;

    constructor(role: Role, cfg: TcpConfig) {
        super();
        this.role = role;
        this.cfg = {
            port: cfg.port,
            host: cfg.host ?? '',
            autoReconnect: cfg.autoReconnect ?? true,
            heartbeatIntervalMs: cfg.heartbeatIntervalMs ?? 5000,
            heartbeatPayload: cfg.heartbeatPayload ?? '__ping__',
            readIdleTimeoutMs: cfg.readIdleTimeoutMs ?? 15000,
            backoff: {
                initialMs: cfg.backoff?.initialMs ?? 1000,
                maxMs: cfg.backoff?.maxMs ?? 15000,
                factor: cfg.backoff?.factor ?? 1.8,
                jitter: cfg.backoff?.jitter ?? 0.2,
            },
        };

        // 监听 App 前后台/网络切换，做重连
        AppState.addEventListener('change', this.onAppState);
        NetInfo.addEventListener(this.onNetChange);
    }

    /** 启动 */
    async start() {
        if (this.role === 'server' || this.role === 'both') this.startServer();
        if ((this.role === 'client' || this.role === 'both') && this.cfg.host) this.startClient();
    }

    /** 停止并清理 */
    stop() {
        this.clearHeartbeat();
        this.clearIdleTimer();
        this.clearReconnectTimer();

        this.serverSocket?.destroy();
        this.serverSocket = null;

        this.client?.destroy();
        this.client = null;

        this.server?.close();
        this.server = null;
    }

    /** 当前是否已连接（任一方向） */
    get connected() {
        return !!(this.client && (this as any).client?.destroyed === false) ||
            (!!this.serverSocket && (this as any).serverSocket?.destroyed === false);
    }

    /** 发送数据（自动挑选连接：优先客户端连接，其次服务端的已接入 socket） */
    send(data: string | Uint8Array) {
        const sock = this.client?.destroyed === false ? this.client
            : this.serverSocket?.destroyed === false ? this.serverSocket
                : null;
        if (!sock) throw new Error('No active socket');
        if (typeof data === 'string') sock.write(data);
        else sock.write(Buffer.from(data));
    }

    /** ========== 内部：服务端 ========== */
    private startServer() {
        if (this.server) return;
        const server = TcpSocket.createServer((socket) => {
            // 如果只支持单连接，可踢掉旧连接
            this.serverSocket?.destroy();
            this.serverSocket = socket;

            this.emit('server:client_connected', { address: socket.address() });
            this.resetIdleTimer();
            this.startHeartbeat();

            socket.on('data', (buf) => {
                this.emit('data', buf);
                this.resetIdleTimer();
                // 简易心跳回应
                if (this.isHeartbeat(buf)) socket.write('__pong__');
            });

            socket.on('error', (e) => this.emit('error', e));
            socket.on('close', () => {
                this.emit('server:client_disconnected');
                this.clearIdleTimer();
                this.serverSocket = null;
            });
        });

        server.on('error', (e) => {
            this.emit('error', e);
            // 端口被占用等情况，延迟重试
            setTimeout(() => { this.server?.close(); this.server = null; this.startServer(); }, 2000);
        });

        server.listen({ port: this.cfg.port, host: '0.0.0.0' }, () => {
            this.emit('server:ready', { port: this.cfg.port });
        });

        this.server = server;
    }

    /** ========== 内部：客户端 ========== */
    private startClient() {
        if (this.client && (this as any).client?.destroyed === false) return;

        const client = TcpSocket.createConnection(
            { port: this.cfg.port, host: this.cfg.host, tls: false },
            () => {
                this.emit('client:connected', { host: this.cfg.host, port: this.cfg.port });
                this.resetBackoff();
                this.startHeartbeat();
                this.resetIdleTimer();
            },
        );

        client.on('data', (buf) => {
            this.emit('data', buf);
            this.resetIdleTimer();
        });

        client.on('error', (e) => {
            this.emit('error', e);
        });

        client.on('close', () => {
            this.emit('client:disconnected');
            this.clearIdleTimer();
            this.clearHeartbeat();
            if (this.cfg.autoReconnect) this.scheduleReconnect();
        });

        this.client = client;
    }

    /** 计划重连（指数退避） */
    private scheduleReconnect() {
        if (this.reconnectTimer) return;
        const d = this.nextBackoff();
        this.reconnectTimer = setTimeout(() => {
            this.reconnectTimer = null;
            // 仅在前台且有网络时重连
            if (this.appState === 'active') this.startClient();
            else this.scheduleReconnect();
        }, d);
        this.emit('client:reconnect_scheduled', { delayMs: d });
    }

    private resetBackoff() { this.reconnectDelay = 0; }
    private nextBackoff() {
        const { initialMs, maxMs, factor, jitter } = this.cfg.backoff;
        const next = this.reconnectDelay ? Math.min(maxMs, this.reconnectDelay * factor) : initialMs;
        const rand = next * (1 + (Math.random() * 2 - 1) * jitter);
        this.reconnectDelay = next;
        return Math.round(rand);
    }
    private clearReconnectTimer() { if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = null; } }

    /** ========== 心跳与空闲检测 ========== */
    private startHeartbeat() {
        if (this.hbTimer || this.cfg.heartbeatIntervalMs <= 0) return;
        const sendBeat = () => {
            try { if (this.connected) this.send(this.cfg.heartbeatPayload); } catch {}
        };
        this.hbTimer = setInterval(sendBeat, this.cfg.heartbeatIntervalMs);
    }
    private clearHeartbeat() { if (this.hbTimer) { clearInterval(this.hbTimer); this.hbTimer = null; } }
    private isHeartbeat(buf: Uint8Array) {
        try {
            const s = Buffer.from(buf).toString();
            return s === this.cfg.heartbeatPayload;
        } catch { return false; }
    }

    private resetIdleTimer() {
        this.clearIdleTimer();
        if (!this.cfg.readIdleTimeoutMs || this.cfg.readIdleTimeoutMs <= 0) return;
        this.idleTimer = setTimeout(() => {
            this.emit('idle_timeout');
            // 强制断开，触发重连
            if (this.client && (this as any).client?.destroyed === false) this.client?.destroy();
            if (this.serverSocket && (this as any).serverSocket?.destroyed === false) this.serverSocket?.destroy();
        }, this.cfg.readIdleTimeoutMs);
    }
    private clearIdleTimer() { if (this.idleTimer) { clearTimeout(this.idleTimer); this.idleTimer = null; } }

    /** ========== App/网络状态 ========== */
    private onAppState = (s: AppStateStatus) => {
        this.appState = s;
        if (s === 'active') {
            // 回到前台尝试重连
            if ((this.role === 'client' || this.role === 'both') && this.cfg.host && !this.connected) {
                this.clearReconnectTimer();
                this.scheduleReconnect();
            }
        } else {
            // 后台可选择断开以省电
            // this.stop();
        }
    };

    private onNetChange = (state: any) => {
        if (!state.isConnected) {
            // 断网：清理 socket
            this.client?.destroy(); this.serverSocket?.destroy();
        } else {
            // 恢复网络：尝试重连
            if ((this.role === 'client' || this.role === 'both') && this.cfg.host && !this.connected) {
                this.clearReconnectTimer();
                this.scheduleReconnect();
            }
        }
    };
}
export default TcpLink;
